﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AlgoritmoConstrutivo.entidades
{
    [Serializable]
    public class No : IComparable
    {
        private int id;
        private String nome;
        private Double grau;
       
        private object _sync = new object();
        private int numMaximoConexoesVizinhos = -1;
        private int numAtualConexoesVizinhos = -1;
        private Cluster cluster; 
        private Vizinhos arestasQueSaem = null;
        private Vizinhos arestasQueEntram = new Vizinhos();

  
        public No() 
        {
        }

        public override string ToString()
        {
            if (this.cluster!=null)
                return (this.nome + "_" + this.id + "encontra-se no CLUSTER de ID " +this.cluster.Id);

            return (this.nome + "_" + this.id);
        }

        public override bool Equals(object obj)
        {
            return ((obj as No).id == this.id);
        }

        public No(int id, String nome) : this(id, new Vizinhos(),nome)
        {
        }

        public No(int id) : this(id, new Vizinhos(),null) 
        {
        }

        public No(int id, Vizinhos neighbors, String nome)
        {
            this.id = id;
            this.arestasQueSaem = neighbors;
            this.nome = nome;
        }

     
        internal void LimpaNos()
        {
            this.cluster = null;
            //this.arestasQueEntram = 0;
            //this.arestasQueSaem = 0;
        }

        internal void ConfiguraCluster(Cluster clu, Grafo software)
        {
            lock (_sync)
            {
              
                 if (clu == null)
                        throw new NullReferenceException("Tentou-se configurar o nó " + this.id + " com um cluster nulo");

                    this.cluster = clu;
                

                if (software.RetornaNo(this.id).cluster == null)
                    software.RetornaNo(this.id).cluster = this.cluster;

                try
                {
                    this.cluster.AdicionarNo(this.id, software);
                }
                catch (Exception ex)
                {
                
                    throw ex;
                }
             }
        }

        internal void CalculaGrau()
        {
            if (this.numAtualConexoesVizinhos == 0 || this.numAtualConexoesVizinhos == -1)
            {
                this.grau = 0;
                return;
            }

            int numMaximoConexoes = ((this.arestasQueSaem.Count) * (this.arestasQueSaem.Count - 1));


            if (this.numAtualConexoesVizinhos > numMaximoConexoes)
                throw new Exception(" O nó " + this.nome + " possui uma inconsistência no seu cálculo de grau");
            else
                this.grau = Math.Round( (double)this.numAtualConexoesVizinhos / numMaximoConexoes,2);
        }

        public int NumAtualConexoesVizinhos
        {
            get { return numAtualConexoesVizinhos; }
            set
            {
                if (value < 0)
                    throw new Exception("Tentou-se configurar um valor negativo para o numero atual de conexoes dos vizinhos do no " + this.nome);

                numAtualConexoesVizinhos = value;

                this.CalculaGrau();

            }
        }

    
        public int CompareTo(object obj)
        {
            No n = obj as No;

            if (n.ArestasQueSaem.Count > this.ArestasQueSaem.Count)
                return 1;

            else if (n.ArestasQueSaem.Count == this.ArestasQueSaem.Count)
                return 0;
            else
                return -1;
        }

   

        public int Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }

        public Vizinhos ArestasQueSaem
        {
            get
            {
                return arestasQueSaem;
            }
            set
            {
                arestasQueSaem = value;
            }
        }

        public Vizinhos ArestasQueEntram
        {
            get { return arestasQueEntram; }
            set { arestasQueEntram = value; }
        }

        public Cluster Cluster
        {
            get { return cluster; }

        }

        public Double Grau
        {
            get { return grau; }
        }

        public String Nome
        {
            get { return nome; }
            set { nome = value; }
        }
    }
}
